package com.code.soulnetty.modbus.biz;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.stream.Collector;

/**
 * @author lyf
 * @date 2022-12-17 15:49
 */
public class Utils {
    /**
     * -------------------配置文件key 开始------------------------
     */

    public static final String TENANT_ID = "tenant.id";

    public static final String REDIS_HOST = "redis.host";
    public static final String REDIS_PORT = "redis.port";
    public static final String REDIS_CONNTIMEOUT = "redis.connTimeout";
    public static final String REDIS_USER = "redis.user";
    public static final String REDIS_PASSWORD = "redis.password";


    public static final String HTTP_CLIENT_PRE = "http.client";
    public static final String HTTP_CLIENT_BASE_URL = "baseUrl";
    public static final String HTTP_CLIENT_SERVICE_CLASS = "serviceClass";
    public static final String HTTP_CLIENT_LOG = "log";

    public static final String CONFIG_CACHE_PATH = "config.cache.path";


    public static final String MY_ID = "my.id";
    public static final String MY_ALGORITHM = "my.allocation.algorithm";

    public static final String ZK_HOST = "zk.hosts";

    public static final String VERSION_REDIS_PRE = "default._config_.CHANNEL.";
    public static final String BLOCK = "my.block";

    /**
     * 版本号相同的error_code
     */
    public static final int EQ_ERR_CODE = 101;
    /**
     * 设备点位key值前缀
     */
    public static final String DP_PRE = "K_";
    public static final String UL = "_";
    public static final String DEFAULT_TENANT = "default";

    /**
     * 数据获取策略
     */
    public static final String ODCC_STRATEGY_MODE = "odcc.startegy.mode";
    public static final String ODCC_CLIENT_BIZID_KEY = "odcc.client.bizId";
    public static final String ODCC_CLIENT_USECASE_KEY = "odcc.client.useCase";
    public static final String ODCC_CLIENT_SCENARIO_KEY = "odcc.client.secnario";
    public static final String ODCC_CLIENT_ALARM_ENABLED = "odcc.client.alarm.subscribe";

    public static final String ODCC_SERVICE_BIZID_KEY = "odcc.service.bizId";
    public static final String ODCC_SERVICE_USECASE_KEY = "odcc.service.useCase";
    public static final String ODCC_SERVICE_SCENARIO_KEY = "odcc.service.secnario";
    public static final String ODCC_ALARM_SERVICE_SCENARIO_KEY = "odcc.alarm.service.secnario";

    public static final String ODCC_UPLOAD_BIZID_KEY = "odcc.upload.bizId";
    public static final String ODCC_UPLOAD_USECASE_KEY = "odcc.upload.useCase";
    public static final String ODCC_UPLOAD_SCENARIO_KEY = "odcc.upload.secnario";

    public static final String ODCC_SPACE_TOPIC = "odcc.space.topic";
    public static final String ODCC_DEVICE_TOPIC = "odcc.device.topic";
    public static final String ODCC_POINT_TOPIC = "odcc.point.topic";
    public static final String ODCC_ALARM_TOPIC = "odcc.alarm.topic";
    public static final String ODCC_POINT_DATA_TOPIC = "odcc.point.data.topic";
    public static final String ODCC_ONLY_ALARM_TOPIC = "odcc.only.alarm.topic";

    /**
     * 阳高场景特殊处理
     */
    public static final String ODCC_SPACE_TOPIC_V = "bytedance-space";


    /**
     * -------------------配置文件key 结束------------------------
     */

    public static final String COMMA = ",";

    public static final String CACHE_ERR = "CACHE_ERR";

    /**
     * 当前节点采集的通道
     */
    public static final String MY_CHANNEL = "MY_CHANNEL";

    /**
     *
     */
    public static final String TEST = "my.test";
    /**
     * 发送数据的topic前缀
     */
    public static final String TOPIC_PRE = "point-data-";

    /**
     * 采集协议
     */
    public static final String P_ODCC = "ODCC";
    public static final String P_ODCC_ONE = "ODCC_ONE";
    public static final String P_B_ONE = "B1";
    public static final String P_B = "B";
    public static final String P_MODBUS_TCP = "MODBUS_TCP";
    public static final String P_MODBUS_TCP_SYNC = "MODBUS_TCP_SYNC";
    public static final String P_BACNET = "BACNET";
    public static final String P_SNMP_V2C = "SNMP_v2c";
    public static final String P_SNMP_V3 = "SNMP_v3";
    public static final String HIK_AM = "HIK_AM";
    public static final String P_GUOHUA_HTTP_A = "GUOHUA_HTTP_A";
    public static final String P_GUOHUA_HTTP_B = "GUOHUA_HTTP_B";

    /**
     * 调度采集参数
     */
    public static final String SCHEDULE_THREAD_POOL_SIZE = "SCHEDULE_THREAD_POOL_SIZE";
    public static final String TOTAL_PERIOD_COUNT = "TOTAL_PERIOD_COUNT";
    public static final String RATE_THREAD_POOL_SIZE = "RATE_THREAD_POOL_SIZE";
    public static final String RATE_QUEUE_SIZE = "RATE_QUEUE_SIZE";
    public static final String OFFLINE_THREAD_POOL_SIZE = "OFFLINE_THREAD_POOL_SIZE";
    public static final String OFFLINE_QUEUE_SIZE = "OFFLINE_QUEUE_SIZE";
    public static final String OFFLINE_TIME = "OFFLINE_TIME";
    public static final String THRESHOLD_TIME = "THRESHOLD_TIME";

    /**
     * useCase, scenario of Extension
     */
    public static final String BACNET_USE_CASE = "bacnet";
    public static final String BACNET_SCENARIO = "pull";

    public static final String SNMP_USE_CASE = "snmp";
    public static final String SNMP_SCENARIO = "pull";

    public static final String GUOHUA_HTTP_A_USE_CASE = "guoHuaHttpA";
    public static final String GUOHUA_HTTP_A_SCENARIO = "pull";

    /**
     * 采集周期KEY（秒）
     */
    public static final String PERIOD = "PERIOD";
    /**
     * 采集重试次数
     */
    public static final String RETRY_COUNT_STR = "RETRY_COUNT";
    /**
     * 轮询间隔时间（毫秒）
     */
    public static final String REQ_INTL = "REQ_INTL";
    /**
     * 超过时间
     */
    public static final String TIME_OUT = "TIME_OUT";

    /**
     * 任务类型, RATE/DELAY
     */
    public static final String TASK_TYPE = "TASK_TYPE";

    /**
     * 链接超过时间
     */
    public static final String CONN_TIME_OUT = "CONN_TIME_OUT";

    /**
     * 源端口
     */
    public static final String SOURCE_PORT = "SOURCE_PORT";

    /**
     * BACNET单个请求批量处理点位数量
     */
    public static final String BACNET_REQ_BATCH_SIZE = "BACNET_REQ_BATCH_SIZE";

    /**
     * SNMP单个请求批量处理点位数量
     */
    public static final String SNMP_REQ_BATCH_SIZE = "SNMP_REQ_BATCH_SIZE";

    /**
     * 默认BACNET单个请求批量处理点位数量
     */
    public static final int DEFAULT_BACNET_REQ_BATCH_SIZE = 50;

    /**
     * snmp协议默认community
     */
    public static final String DEFAULT_SNMP_COMMUNITY = "public";

    /**
     * 默认SNMP单个请求批量处理点位数量
     */
    public static final int DEFAULT_SNMP_REQ_BATCH_SIZE = 20;

    /**
     * 采集周期时间
     */
    public static final int DEFAULT_PERIOD = 10;
    /**
     * 采集重试次数
     */
    public static final int DEFAULT_RETRY_COUNT = 3;
    /**
     * 默认任务类型
     */
    public static final String DEFAULT_TASK_TYPE = "DELAY";
    /**
     * 轮询间隔时间（毫秒）
     */
    public static final long DEFAULT_REQ_INTL = 50;
    /**
     * 超过时间
     */
    public static final long DEFAULT_TIME_OUT = 100;
    /**
     * 链接超时时间
     */
    public static final int DEFAULT_CONN_TIME_OUT = 500;

    /**
     * 默认源端口为0, 操作系统从所有可用端口中随机选取
     */
    public static final int DEFAULT_SOURCE_PORT = 0;

    /**
     * 处理自增
     */
    private static final Map<String, AtomicInteger> RECORD = new ConcurrentHashMap<>();

    private Utils() {
    }

    public static short nextShort(String msgKey) {
        final AtomicInteger atomicInteger = RECORD.computeIfAbsent(msgKey, t -> new AtomicInteger(0));
        return (short) atomicInteger.incrementAndGet();
    }


    /**
     * 16位byte值
     */
    public static final byte[] HEX_NUM = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

    static final Set<Collector.Characteristics> CH_ID =
            Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));

    public static <K, V> Collector<Map<K, V>, ?, Map<K, V>> toMap(BiFunction<V, V, V> biConsumer) {
        return new CollectorImpl<>(HashMap::new, (kvMap, kvMap2) -> kvMap2.forEach((k, v) -> {
            kvMap.computeIfPresent(k, (kk, vv) -> biConsumer.apply(v, vv));
            kvMap.computeIfAbsent(k, d -> v);
        }), (kvMap, kvMap2) -> {
            kvMap2.forEach((k, v) -> {
                kvMap.computeIfPresent(k, (kk, vv) -> biConsumer.apply(v, vv));
                kvMap.computeIfAbsent(k, d -> v);
            });
            return kvMap;
        }, Function.identity(), CH_ID);
    }

    public static <T> Collector<T, ?, TreeSet<T>> toTreeSet(Comparator<T> comparator) {
        return new CollectorImpl<>(() -> new TreeSet<>(comparator), TreeSet::add, (left, right) -> {
            left.addAll(right);
            return left;
        }, Function.identity(), CH_ID);
    }

    public static String bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toLowerCase();
        }
        return ret;
    }

    public static byte[] hexStr2Bytes(String src) {
        src = src.trim().replaceAll("\n| ", "").toLowerCase();
        int m, n;
        int iLen = src.length() / 2;
        byte[] ret = new byte[iLen];

        for (int i = 0; i < iLen; i++) {
            m = i * 2 + 1;
            n = m + 1;
            ret[i] = (byte) (Integer.decode("0x" + src.substring(i * 2, m) + src.substring(m, n)) & 0xff);
        }
        return ret;
    }

    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
        Supplier<A> supplier;
        BiConsumer<A, T> accumulator;
        BinaryOperator<A> combiner;
        Function<A, R> finisher;
        Set<Characteristics> characteristics;

        public CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
                             Function<A, R> finisher, Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
        }

        @Override
        public Supplier<A> supplier() {
            return supplier;
        }

        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }

        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }

        @Override
        public Function<A, R> finisher() {
            return finisher;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    }
}
